package edu.ustb.linehash;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author ShiZhe
 * @create 2020-10-08 14:03
 */
public class LineHash {

    public int pageSize;  //桶的容量

    public int overPoint = 0; //分裂点

    public int listSize = 4; //哈希表的初始大小

    public int initlistSize = 4; //哈希大小的记录值

    public int workRound = 1;  //分裂轮数

    public List<Map<Integer, String>> hash = null; //模拟哈希表

    public LineHash(int pageSIze) {
        this.pageSize = pageSIze;
        hash = new ArrayList<Map<Integer, String>>(4);
        for (int i = 0; i < listSize; i++) {
            hash.add(new HashMap<Integer, String>()); //向哈希表中初始化桶
        }
    }
    //查询函数
    public String getKeyValue(int key){
        int index = hashFun(key, workRound); //根据分裂轮数调用不同的哈希函数
        if(index < overPoint){				//当前桶产生了分裂
            index = hashFun(key, workRound + 1); //采用新的哈希函数进行计算
        }
        return hash.get(index).get(key);
    }
    //添加函数
    public void addKeyValue(int key, String value) {
        int index = hashFun(key, workRound);
        if(index < overPoint){
            index = hashFun(key, workRound + 1);
        }
        Map<Integer, String> map = hash.get(index);
        if (map.size() < pageSize) {   //判断当前桶是否满了
            map.put(key, value);
        } else {
            map.put(key, value);
            splitHash();              //满了就进行分裂
        }
    }

    public int hashFun(int key, int f1) {
        return key % (4 * f1);
    }

    public void splitHash() {
        Map<Integer, String> OldMap = hash.get(overPoint);   //旧桶
        Map<Integer, String> NewMap = new HashMap<Integer, String>(); //分裂产生的新桶

        Integer[] keyList = OldMap.keySet().toArray(new Integer[0]);
        for (int i = 0; i < keyList.length; i++) {  //准备移动一半的数据到新桶
            int key = keyList[i].intValue();
            int index = hashFun(key, workRound + 1);
            if (index >= listSize) {
                String value = OldMap.get(key);
                OldMap.remove(key);
                NewMap.put(key, value);
            }
        }
        hash.add(NewMap);  //将新桶放入哈希表
        listSize++;  //哈希表长度增加
        overPoint++;  //分裂点移动
        if(overPoint >= initlistSize){  //分裂点移动了一轮就更换新的哈希函数
            workRound++;
            initlistSize = initlistSize * 2;
            overPoint = 0;
        }
    }
}